home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1998 July / EnigmA AMIGA RUN 29 (1998)(G.R. Edizioni)(IT)[!][issue 1998-07 & 08].iso / cd-sup / updatecopy / source / updatecopy.e
Text File  |  1998-05-24  |  26KB  |  841 lines

  1. /* UpDateCopy.e
  2. ** Copies multiple files/directories to one destination.
  3. ** Not existing directories are created.
  4. ** Already existing files are only replaced by newer ones
  5. ** (UpDateCopy first checks for versions-string and then
  6. **  for dates).
  7. **
  8. ** $VER: UpDateCopy.e 0.52 (21.02.97)
  9. **
  10. ** This program is Cardware. If you use it you should send an Email to
  11. ** the author. Also small presents are very welcome.
  12. ** You may use this sourcefile or parts of it freely in your programs.
  13. ** But please do not spread a modified version under this name (UpDateCopy).
  14. ** For Bugreports, ideas or anything else send a Email to:
  15. **    ss37@irz.inf.tu-dresden.de
  16. ** 
  17. ** Sven Steiniger, 1996, 1997
  18. **
  19. ** Fold-start: ->// ""
  20. ** Fold-stop:  ->\\
  21. **
  22. ** History:
  23. **  0.52: - improved SMARTINFO-option
  24. **  0.51: - removed bug of version-scan-routines
  25. **  0.50: - added FAST-option
  26. **  0.49: - added SMARTINFO option
  27. **        - added wildcard-check. Now you can also use '*' as wildcard and
  28. **          you can also pass devices as sources (eq. ram:)
  29. **  0.48: - used exthelp-feature OF ReadArgs()
  30. **        - no longer needs 'c:copy'-command. Implemented an own routine.
  31. **  0.47: - file was not closed before SetProtection()/SetFileDate()
  32. **  0.46: - added PAPF-option -> archive protection flag is not changed
  33. **  0.45: - added CLONE-option -> Datestamp is copied
  34. **  0.44: - removed a unnecessary module. Saves 1K of executable size!
  35. **        - removed unnecessary ExamineFH()
  36. **        - now file gets only examined if really necessary
  37. **        - optimized a bit
  38. **        - FIXED: TESTMODE was buggy -> Directories were still created.
  39. **  0.43: - add new option TESTMODE; dont copy/replace files
  40. **  0.42: - add new option NODATECHECK; dont compare datestamps
  41. **  0.41: - replaced ALL reads/writes by fread/fwrite
  42. **  0.40: - first PUBLIC release
  43. */
  44.  
  45. OPT OSVERSION=37
  46. OPT REG=5
  47.  
  48. MODULE 'dos/dos','dos/dosasl','dos/dostags','dos/rdargs'
  49.  
  50. RAISE "MEM"  IF String()=NIL,
  51.       "addp" IF AddPart()=DOSFALSE,
  52.       "^C"   IF CtrlC()=TRUE,
  53.       "copy" IF FileLength()=-1,
  54.       "MEM"  IF AllocDosObject()=NIL,
  55.       "fatt" IF SetProtection()=DOSFALSE,
  56.       "fatt" IF SetComment()=DOSFALSE,
  57.       "fatt" IF SetFileDate()=DOSFALSE
  58.  
  59. CONST MAXPATH=255,                -> Maximum path length
  60.       SPACEADD=3,                 -> Number of spaces per indent
  61.       SAFETYBYTES=100,            -> Maximum length of versionstring
  62.       BIGFILEMEM=100000           -> Files bigger than that are not read
  63.                                   -> completly into memory
  64.  
  65. CONST PATHLENGTH=MAXPATH-1,
  66.       BIGFILESIZE=BIGFILEMEM-SAFETYBYTES
  67.                                   
  68.  
  69. ENUM PDIR_Error,
  70.      PDIR_Skipped,
  71.      PDIR_Created
  72.  
  73. ENUM PFILE_Error,
  74.      PFILE_Skipped,
  75.      PFILE_Copied,
  76.      PFILE_Replaced
  77.  
  78. DEF frompath[MAXPATH]:STRING,     -> actual sourcepath
  79.     fromlist:PTR TO LONG,         -> pointer to array of sourcestrings
  80.     topath[MAXPATH]:STRING,       -> destinationpath
  81.     doinfo,                       -> should we write informations ?
  82.     recursiv,                     -> scan recursively through subdirectories ?
  83.     ignoreprotection,             -> clear delete-protection ?
  84.     checkversion,                 -> compare version-strings ?
  85.     checkdates,                   -> compare datestamps ?
  86.     testmode,                     -> test modus ? (do not copy/replace files)
  87.     clone,                        -> copy datestamp ?
  88.     cleararchivebit,              -> clear archivebit OF copied file
  89.     smartinfo,                    -> only display copied/replaced files
  90.     fastdisplay,                  -> no linefeed
  91.     dirlock=NIL                   -> PTR TO lock-structure OF destination path
  92.  
  93. PROC main() HANDLE
  94. ->// "main()"
  95. DEF rdargs=NIL,
  96.     myargs:PTR TO LONG,
  97.     template,
  98.     myrdargs=NIL:PTR TO rdargs,
  99.     exthelp[1000]:STRING
  100.  
  101.   /* Initialize argument-array */
  102.   myargs:=[
  103.            NIL,           -> fromlist
  104.            NIL,           -> destination path
  105.            FALSE,         -> ~showinfo
  106.            FALSE,         -> scan recursiv throuhg subdirectories
  107.            FALSE,         -> ignore protectionbits
  108.            FALSE,         -> deep scan
  109.            FALSE,         -> ~compare datestamps
  110.            FALSE,         -> testmode
  111.            FALSE,         -> clone
  112.            FALSE,         -> preserve archive protection flag
  113.            FALSE,         -> smartinfo
  114.            FALSE          -> fastdisplay
  115.           ]:LONG    
  116.  
  117.   myrdargs:=AllocDosObject(DOS_RDARGS,NIL)
  118.  
  119.   StrCopy(exthelp, '\n'+
  120.                    '  UpDateCopy v0.52\n'+
  121.                    ' -----------------\n'+
  122.                    '  Copy files and directories.\n'+
  123.                    '  Not existing directories are created and\n'+
  124.                    '  already existing files are only replaced\n'+
  125.                    '  by newer ones. Allows pattern-matching and\n'+
  126.                    '  multiple sourcedirectories/files.\n\n'+
  127.                    'Sven Steiniger, 1996, 1997\n',
  128.           ALL)
  129.   StrAdd(exthelp,  '\n'+
  130.                    '  FROM        - source directory/file(s)\n'+
  131.                    '  TO          - destination directory\n'+
  132.                    '  QUIET       - no outputs\n'+
  133.                    '  ALL         - scans through subdirectories recursively\n'+
  134.                    '  FORCE       - ignore delete-protectionbit\n'+
  135.                    '  DEEP        - compare version-strings\n'+
  136.                    '  NODATECHECK - don''t compare datestamps\n'+
  137.                    '  TESTMODE    - neither copy/replace files nor create directories\n'+
  138.                    '  CLONE       - copy datestamp\n'+
  139.                    '  PAPF        - don''t clear the archive protection flag\n'+
  140.                    '  SMARTINFO   - only displays copied/replaced files\n'+
  141.                    '  FAST        - fast output. No linefeeds\n',
  142.          ALL)
  143.   myrdargs.exthelp:=exthelp
  144.  
  145.   /* Parse Commandline */
  146.   IF rdargs:=ReadArgs(template:='FROM/M,TO/A,QUIET/S,ALL/S,FORCE/S,DEEP/S,'+
  147.                                 'NDC=NODATECHECK/S,TESTMODE/S,CLONE/S,PAPF/S,'+
  148.                                 'SMARTINFO/S,FAST/S',
  149.                       myargs,myrdargs)
  150.  
  151.     /* Copy Datas to global variables */
  152.     fromlist         := myargs[0]
  153.     StrCopy(topath,myargs[1],ALL)
  154.     doinfo           := Not(myargs[2])
  155.     recursiv         := myargs[3]
  156.     ignoreprotection := myargs[4]
  157.     checkversion     := myargs[5]
  158.     checkdates       := Not(myargs[6])
  159.     testmode         := myargs[7]
  160.     clone            := myargs[8]
  161.     cleararchivebit  := Not(myargs[9])
  162.     smartinfo        := myargs[10]
  163.     fastdisplay      := myargs[11]
  164.  
  165.     IF fromlist=NIL THEN Throw("ARGS",'No source specified.')
  166.     init_arguments()
  167.  
  168.     IF doinfo
  169.       PrintF('Updating files to "\s".\n',topath)
  170.       IF testmode THEN PrintF('** Testmode **\n')
  171.     ENDIF
  172.  
  173.     IF fastdisplay
  174.       PrintF('\n')
  175.       smartinfo:=FALSE
  176.     ENDIF
  177.  
  178.     WHILE fromlist[]                     -> 'fromlist' is array of string-pointers
  179.       StrCopy(frompath,fromlist[]++,ALL) -> copy the string and increment 'fromlist'
  180.       checkWildCard(frompath)
  181.       scan_directory(frompath,'',1)    -> then process this directory
  182.     ENDWHILE
  183.  
  184.   ENDIF
  185.  
  186. EXCEPT DO  -> Cleanup
  187.  
  188.   IF fastdisplay THEN reportLine(0,'',NIL,NIL)
  189.  
  190.   free_arguments()
  191.   IF rdargs THEN FreeArgs(rdargs)
  192.   FreeDosObject(DOS_RDARGS,myrdargs)
  193.  
  194.   IF exception
  195.     /* Print error description */
  196.     PrintF('Error: ')
  197.     SELECT exception
  198.       CASE "MEM"  ; PrintF('Not enough memory.\n')
  199.       CASE "addp" ; PrintF('Path too long !?\n')
  200.       CASE "^C"   ; PrintF('User abort.\n')
  201.       CASE "copy" ; PrintF('Could not copy file.\n')
  202.       CASE "open" ; PrintF('Could not open file.\n')
  203.       CASE "anly" ; PrintF('Could not analyse file.\n')
  204.       CASE "fatt" ; PrintF('Could not set file attributes.\n')
  205.       DEFAULT     ; PrintF('\s\n',exceptioninfo)
  206.     ENDSELECT
  207.   ELSE
  208.     PrintF('Finished.\n')
  209.   ENDIF
  210.  
  211.   CleanUp(exception)
  212.  
  213. ENDPROC
  214. ->\\
  215.  
  216. versionstring: CHAR '$VER: UpDateCopy 0.52 (21.02.97)',0
  217.  
  218.  
  219. /* checks the arguments provied by user
  220. */
  221. PROC init_arguments()
  222. ->// "init_arguments()"
  223.  
  224.   IF (dirlock:=Lock(topath,SHARED_LOCK))=NIL            -> check if destination
  225.     Throw("dir",'Could not lock destination directory') -> directory exists
  226.   ENDIF
  227.   /* Enable Version Check if datestamp-check is switch off */
  228.   IF checkdates=FALSE THEN checkversion:=TRUE
  229.  
  230. ENDPROC
  231. ->\\
  232.  
  233. /* handles so special cases with wildcards
  234. ** Parameter:
  235. **   file - file/dir to be checked
  236. */
  237. PROC checkWildCard(file:PTR TO CHAR)
  238. ->// "checkWildCard"
  239. DEF len
  240.  
  241.   len:=StrLen(file)
  242.   IF file[len-1]="*"
  243.     -> replace '*'-wildcard by '#?'
  244.     CopyMem('#?',file+len-1,3)
  245.   ELSEIF file[len-1]=":"
  246.     -> it's an device. Therefore add wildcard
  247.     CopyMem('#?',file+len,3)
  248.   ENDIF
  249.  
  250. ENDPROC
  251. ->\\
  252.  
  253. /* Cleanup datas allocated during init_arguments
  254. */
  255. PROC free_arguments()
  256. ->// "free_arguments()"
  257.   UnLock(dirlock)             -> Unlock destination directory
  258. ENDPROC
  259. ->\\
  260.  
  261.  
  262. /* Scans a directory and copies files/creates subdirectories
  263. ** Parameter:
  264. **   directory    - name of directory to be scanned
  265. **   path         - the current delta path
  266. **   depth        - recursion level
  267. ** Example:
  268. **   The source path is "esource:src".
  269. **   'directory' is "esource:src/tools/file".
  270. **   Then 'path' have to be "tools/file".
  271. */
  272. PROC scan_directory(directory,path,depth) HANDLE
  273. ->// "scan_directory()"
  274. DEF info:PTR TO fileinfoblock,
  275.     anchor=NIL:PTR TO anchorpath,
  276.     error,
  277.     fullpath,
  278.     mypath[MAXPATH]:STRING,
  279.     length
  280.  
  281.   /* Create and initialize anchor structure needed for
  282.   ** scanning through directory.
  283.   ** This structure has no fixed size.
  284.   */
  285.   anchor:=NewR(SIZEOF anchorpath+MAXPATH)
  286.   anchor.strlen:=PATHLENGTH
  287.  
  288.   -> Get start of string
  289.   fullpath:=anchor+SIZEOF anchorpath
  290.  
  291.   error:=MatchFirst(directory,anchor)
  292.   WHILE error=DOSFALSE
  293.  
  294.     CtrlC()
  295.  
  296.     info:=anchor.info                           -> get fileinfoblock
  297.     IF info.direntrytype>0                      -> is it a directory ?
  298.  
  299.       StrCopy(mypath,path,ALL)                  -> init new delta path
  300.       AddPart(mypath,info.filename,PATHLENGTH)  -> including new subdirectory
  301.  
  302.       process_directory(fullpath,info,mypath,   -> knows what to do with this
  303.                         depth*SPACEADD)         -> directory
  304.  
  305.       IF recursiv                               -> scan subdirectories ?
  306.         length:=StrLen(fullpath)
  307.         IF (length+5)<MAXPATH
  308.           CopyMem('/#?',fullpath+length,4)      -> add pattern matching
  309.         ENDIF
  310.         scan_directory(fullpath,mypath,depth+1) -> call our self with new subdirectory
  311.         fullpath[length]:=0                     -> remove pattern matching
  312.       ENDIF
  313.  
  314.     ELSE
  315.  
  316.       process_file(fullpath,info,path,          -> knows what to do with it
  317.                    depth*SPACEADD)
  318.  
  319.     ENDIF
  320.  
  321.     error:=MatchNext(anchor)                    -> Next entry
  322.   ENDWHILE
  323.  
  324. EXCEPT DO
  325.  
  326.   IF anchor
  327.     MatchEnd(anchor)                            -> Clean up
  328.     Dispose(anchor)
  329.   ENDIF
  330.  
  331.   ReThrow()
  332.  
  333. ENDPROC
  334. ->\\
  335.  
  336.  
  337. /* takes care of fastdisplay-option
  338. */
  339. PROC reportLine(spaceanz,fmtstr,arg1,arg2)
  340.  
  341.   IF fastdisplay
  342.     PrintF([141,$1b,"[","M",0]:CHAR)
  343.     spaceanz:=SPACEADD
  344.   ENDIF
  345.   WHILE spaceanz-->=0 DO FputC(stdout," ")
  346.   PrintF(fmtstr,arg1,arg2)                 -> Write directory name & status
  347.   PrintF('\n')
  348.  
  349. ENDPROC
  350.  
  351. /* Prints a directory status.
  352. ** Parameter:
  353. **   spaces - number of leading spaces
  354. **   status - status (PDIR_Error, PDIR_Skipped, PDIR_Created)
  355. **   path   - directory path
  356. */
  357. PROC printDirStatus(spaces,status,path)
  358. ->// "printDirStatus()"
  359. DEF stri
  360.  
  361.   IF doinfo
  362.     SELECT status
  363.       CASE PDIR_Created ; stri:='created'
  364.       CASE PDIR_Skipped ; IF smartinfo THEN RETURN  -> don't display skipped dirs with smartinfo
  365.                           stri:='skipped'
  366.       DEFAULT           ; stri:='Error!!'
  367.     ENDSELECT
  368.     reportLine(spaces,'\e[1m\s\e[0m..\s',path,stri) -> Write directory name & status
  369.   ENDIF
  370.  
  371. ENDPROC
  372. ->\\
  373.  
  374. /* Process an directory. If it doesnt exists it will be created
  375. ** Parameter:
  376. **  directory - full path of source directory
  377. **  info      - pointer to fileinfoblock of source directory
  378. **  path      - delta path of directory
  379. */
  380. PROC process_directory(directory,info:PTR TO fileinfoblock,path,spaces)
  381. ->// "process_directory()"
  382. DEF stri[MAXPATH]:STRING,
  383.     lock
  384.  
  385.   StrCopy(stri,topath,ALL)
  386.   AddPart(stri,path,PATHLENGTH)                  -> thats the destion-directory
  387.  
  388.   IF lock:=Lock(stri,SHARED_LOCK)                -> Exists this Directory ?
  389.     printDirStatus(spaces, PDIR_Skipped, path)
  390.     UnLock(lock)                                 -> Unlock directory
  391.  
  392.   ELSEIF testmode                                -> Don't create directory in testmode
  393.     printDirStatus(spaces, PDIR_Created, path)   -> but write out a info
  394.  
  395.   ELSEIF lock:=CreateDir(stri)                   -> Create the directory
  396.     printDirStatus(spaces, PDIR_Created, path)
  397.     UnLock(lock)                                 -> No erros, unlock directory
  398.     copyAdditionalInformations(stri,info)
  399.  
  400.   ELSE                                           -> Directory could not be created
  401.     printDirStatus(spaces, PDIR_Error, path)     -> as it does not exists before
  402.     Throw("dir",'Could not create directory')    -> something went wrong
  403.   ENDIF
  404.  
  405. ENDPROC
  406. ->\\
  407.  
  408.  
  409.  
  410. /* Prints a file status.
  411. ** Parameter:
  412. **   spaces - number of leading spaces
  413. **   status - status (PFILE_Error, PFILE_Skipped, PFILE_Created, PFILE_Skipped)
  414. **   file   - filename
  415. */
  416. PROC printFileStatus(spaces,status,file)
  417. ->// "printFileStatus()"
  418. DEF stri
  419.  
  420.   IF doinfo
  421.     SELECT status
  422.       CASE PFILE_Copied   ; stri:='copied'
  423.       CASE PFILE_Replaced ; stri:='replaced'
  424.       CASE PFILE_Skipped  ; IF smartinfo THEN RETURN -> don't display skipped dirs with smartinfo
  425.                             stri:='skipped'
  426.       DEFAULT             ; stri:='Error!!'
  427.     ENDSELECT
  428.     reportLine(spaces,'\s..\s',file,stri)            -> Write file status
  429.   ENDIF
  430.  
  431. ENDPROC
  432. ->\\
  433.  
  434. /* Processes an file. If it does not exists or is newer it is copied.
  435. ** Parameter:
  436. **   file  - full source filename (include path)
  437. **   info  - ptr to fileinfoblock of sourcefile
  438. **   path  - deltapath to directory (exclude filename !)
  439. */
  440. PROC process_file(file,info:PTR TO fileinfoblock,path,spaces) HANDLE
  441. ->// "process_file()"
  442. DEF stri[MAXPATH]:STRING,
  443.     filepath[MAXPATH]:STRING,
  444.     fh=NIL,
  445.     toinfo=NIL:PTR TO fileinfoblock,
  446.     result=0,
  447.     frombuf=NIL
  448.  
  449.   StrCopy(filepath,path,ALL)                             -> create deltapath
  450.   AddPart(filepath,info.filename,PATHLENGTH)             -> inclusive filename
  451.  
  452.   StrCopy(stri,topath,ALL)                               -> create full destination
  453.   AddPart(stri,filepath,PATHLENGTH)                      -> filepath
  454.  
  455.   IF fh:=Open(stri,MODE_OLDFILE)                         -> Open destinationfile
  456.  
  457.     IF checkversion THEN result,frombuf:=compareversion(file,stri)
  458.  
  459.     IF checkdates AND (result=0)
  460.       /* Fileinfoblock have to be LONGWORD-aligned therefore
  461.       ** use dos.library to create this
  462.       */
  463.       toinfo:=AllocDosObject(DOS_FIB,NIL)
  464.  
  465.       -> fill fileinfoblock
  466.       IF ExamineFH(fh,toinfo)=DOSFALSE THEN Throw("file",'Could not examine file ?!')
  467.  
  468.       /* Compare versionstrings was either not specified by user
  469.       ** or was not successfull. Therefore Compare filedates if
  470.       ** the user want it.
  471.       */
  472.       result:=CompareDates(toinfo.datestamp,info.datestamp)
  473.     ENDIF
  474.     IF result>0                                        -> fromfile newer than tofile ?
  475.       Close(fh) ; fh:=NIL                              -> close destination
  476.  
  477.       IF ignoreprotection THEN SetProtection(stri,0)   -> Clear protectionflags
  478.                                                        -> if specified
  479.       copyfile(file,info,stri,frombuf)                 -> copy the file
  480.       printFileStatus(spaces, PFILE_Replaced, filepath)
  481.     ELSE
  482.       printFileStatus(spaces, PFILE_Skipped, filepath)
  483.     ENDIF
  484.   ELSE                                                   -> destination does not exists
  485.     copyfile(file,info,stri)                             -> copy file
  486.     printFileStatus(spaces, PFILE_Copied, filepath)
  487.   ENDIF
  488.  
  489. EXCEPT DO  -> Cleanup
  490.  
  491.   /* compareversion() may return the contents of the
  492.   ** sourcefile. We must free this buffer
  493.   */
  494.   IF frombuf THEN Dispose(frombuf)
  495.  
  496.   IF toinfo THEN FreeDosObject(DOS_FIB,toinfo)
  497.   IF fh THEN Close(fh)
  498.  
  499.   IF exception THEN printFileStatus(spaces, PFILE_Error, filepath)
  500.   ReThrow()
  501.  
  502. ENDPROC
  503. ->\\
  504.  
  505.  
  506. /* Copies a file. For files >BIGFILESIZE Bytes c:copy is
  507. ** used.
  508. ** Parameter:
  509. **  fromfile  - full path of sourcefile
  510. **  tofile    - full path of destinationfile
  511. **  frombuf   - Contents of sourcefile. If NIL then sourcefile
  512. **              is read
  513. */
  514. PROC copyfile(fromfile,frominfo:PTR TO fileinfoblock,tofile,frombuf=NIL) HANDLE
  515. ->// "copyfile()"
  516. DEF fhfrom=NIL,
  517.     fhto=NIL,
  518.     length,
  519.     buf=NIL,
  520.     steplength,actlength
  521.  
  522.   IF testmode THEN RETURN
  523.  
  524.   IF (fhfrom:=Open(fromfile,OLDFILE)) AND    -> open sourcefile
  525.      (fhto:=Open(tofile,NEWFILE))            -> open destinationfile
  526.  
  527.     IF (length:=FileLength(fromfile))>BIGFILESIZE
  528.       /* Files >BIGFILESIZE are not read completly into memory but in parts
  529.       ** of BIGFILESIZE Bytes.
  530.       */
  531.  
  532.       /* Alloc new buffer */
  533.       buf:=NewR(BIGFILESIZE)
  534.  
  535.       /* steplength is the length of the current block to be read */
  536.       /* actlength is the position within the file */
  537.       steplength:=actlength:=BIGFILESIZE
  538.  
  539.       REPEAT
  540.         /* Read next block to buffer. If steplength<0 then EOF is reached */
  541.         IF steplength>0
  542.           IF Fread(fhfrom,buf,steplength,1)<1 THEN Raise("copy")
  543.         ENDIF
  544.  
  545.         /* Write buffer to destinationfile */
  546.         IF Fwrite(fhto,buf,steplength,1)<1 THEN Raise("copy")
  547.         
  548.         IF (actlength:=actlength+BIGFILESIZE)>length
  549.           steplength:=length-(actlength-BIGFILESIZE)
  550.         ENDIF
  551.  
  552.         /* Read until version-string was found or EOF */
  553.       UNTIL steplength<=0
  554.  
  555.     ELSE
  556.  
  557.       IF frombuf                               -> we already know the
  558.                                                -> contents of the sourcefile
  559.         /* Write buffer to destinationfile */
  560.         IF Fwrite(fhto,frombuf,length,1)<1 THEN Raise("copy")
  561.       ELSE
  562.         buf:=NewR(length)                      -> alloc new buffer
  563.  
  564.         /* Read sourcefile into buffer */
  565.         IF Fread(fhfrom,buf,length,1)<1 THEN Raise("copy")
  566.         /* Write buffer TO destinationfile */
  567.         IF Fwrite(fhto,buf,length,1)<1 THEN Raise("copy")
  568.       ENDIF
  569.  
  570.     ENDIF
  571.   ELSE                                       -> There went something wrong
  572.     Raise("copy")
  573.   ENDIF
  574.  
  575. EXCEPT DO
  576.  
  577.   IF buf THEN Dispose(buf)
  578.   IF fhfrom THEN Close(fhfrom)
  579.   IF fhto THEN Close(fhto)
  580.  
  581.   ReThrow()
  582.  
  583.   /* Everything went ok. Copy comment, protection flags etc. */
  584.   copyAdditionalInformations(tofile,frominfo)
  585.  
  586. ENDPROC
  587. ->\\
  588.  
  589. /* Copies extra informations like protectionbits, comment etc.
  590. ** 'name' must be a valid File- or Directory path
  591. ** 'info' is the fileinfoblock of the original file/directories
  592. **        (the dates are copied from it)
  593. **
  594. ** Note: the file may not be opened or locked!
  595. */
  596. PROC copyAdditionalInformations(name,info:PTR TO fileinfoblock)
  597. ->// "copyAdditionalInformations()"
  598.  
  599. DEF protection
  600.  
  601.   /* Clear protectionbit (or not) */
  602.   protection:=info.protection
  603.   IF cleararchivebit THEN protection:=protection AND Not(FIBF_ARCHIVE)
  604.  
  605.   SetProtection(name,protection)       -> Copy protection bits
  606.   SetComment(name,info.comment)        -> Copy comment
  607.  
  608.   /* Copy datestamp if clone option is activated */
  609.   IF clone THEN SetFileDate(name,info.datestamp)
  610.  
  611. ENDPROC
  612. ->\\
  613.  
  614.  
  615. /* Compares the version-strings of two files
  616. ** Parameter:
  617. **   fromfile - full path of sourcefile
  618. **   tofile   - full path of destinationfile
  619. **
  620. ** Returns
  621. **   -1 if tofile-version>fromfile-version
  622. **    0 if               =
  623. **    1 if               <
  624. ** *AND* the contents of the sourcefile or NIL
  625. */
  626. PROC compareversion(fromfile,tofile) HANDLE
  627. ->// "compareversion()"
  628. DEF buffer=NIL:PTR TO CHAR,
  629.     version1,base1,
  630.     version2,base2
  631.  
  632.   version2,base2,buffer:=getVersionOfFile(tofile)
  633.   /* We dont need the destination contents. Therefore delete buffer
  634.   */
  635.   IF buffer
  636.     Dispose(buffer)
  637.     buffer:=NIL
  638.   ENDIF
  639.   /* if version is -1 then no version-string was found */
  640.   IF version2=-1 THEN RETURN 0,NIL
  641.  
  642.   version1,base1,buffer:=getVersionOfFile(fromfile)
  643.   IF version1=-1 THEN RETURN 0,buffer
  644.  
  645.   /* Compare the version, reversion of source/destionation
  646.   ** multiply with other base to get same number of signifant numbers
  647.   */
  648.   RETURN IF (version2*base1)>=(version1*base2) THEN -1 ELSE 1,buffer
  649.  
  650. EXCEPT -> Cleanup
  651.  
  652.   IF buffer THEN Dispose(buffer)
  653.   ReThrow()
  654.  
  655. ENDPROC
  656. ->\\
  657.  
  658.  
  659. /* Gets the version-number of a file
  660. ** Parameter:
  661. **   filename - full path of file
  662. ** Returns the version, base and a buffer with the contents of the file
  663. ** (description for version,base see getversion())
  664. ** buffer may be NIL if file was to large
  665. */
  666. PROC getVersionOfFile(filename) HANDLE
  667. ->// "getVersionOfFile()"
  668. DEF fh=NIL,
  669.     buffer=NIL:PTR TO CHAR,
  670.     version,base,
  671.     steplength,filelength,actlength
  672.  
  673.   IF fh:=Open(filename,OLDFILE)
  674.  
  675.     filelength:=FileLength(filename)
  676.     IF filelength>BIGFILEMEM
  677.       /* Files >BIGFILESIZE are not read completly into memory but in parts
  678.       ** of BIGFILESIZE Bytes.
  679.       ** As we may skip a versionstring the last SAFETYBYTES are copied
  680.       ** to start of new BIGFILESIZE block everytime.
  681.       */
  682.  
  683.       /* Alloc new buffer and read filecontents into it */
  684.       buffer:=NewR(BIGFILEMEM)
  685.       IF Fread(fh,buffer,BIGFILEMEM,1)<1 THEN Raise("anly")
  686.  
  687.       /* steplength is the length of the current block to be read */
  688.       steplength:=BIGFILESIZE
  689.       /* actlength is the position within the file */
  690.       actlength:=BIGFILEMEM
  691.  
  692.       REPEAT
  693.  
  694.         /* Get version. If version=-1 then read next block */
  695.         version,base:=getversion(buffer,steplength+SAFETYBYTES)
  696.         IF version=-1
  697.  
  698.           /* The version-string was maybe at the end of buffer
  699.           ** and therfore skipped. Copy the last SAFETYBYTES bytes
  700.           ** to start of buffer to not lose the version-string.
  701.           */
  702.           CopyMem(buffer+steplength,buffer,SAFETYBYTES)
  703.  
  704.           /* Increase actlength. If actlength is greater than filelength
  705.           ** then set steplength to the number of bytes left.
  706.           */
  707.           actlength:=actlength+BIGFILESIZE
  708.           IF actlength>filelength
  709.             steplength:=filelength-(actlength-BIGFILESIZE)
  710.           ENDIF
  711.  
  712.           /* Read next block to buffer. If steplength<0 then EOF is reached */
  713.           IF steplength>0
  714.             IF Fread(fh,buffer+SAFETYBYTES,steplength,1)<1 THEN Raise("anly")
  715.           ENDIF
  716.  
  717.         ENDIF
  718.  
  719.         /* Read until version-string was found or EOF */
  720.       UNTIL (version<>-1) OR (steplength<=0)
  721.  
  722.       Dispose(buffer)
  723.       buffer:=NIL
  724.  
  725.     ELSE
  726.       /* We have got a small file. Load it completly into memory.
  727.       ** Alloc new buffer and read filecontents into it
  728.       */
  729.       buffer:=NewR(filelength)
  730.       IF Fread(fh,buffer,filelength,1)<1 THEN Raise("anly")
  731.  
  732.       /* get versions and reversion of sourcefile */
  733.       version,base:=getversion(buffer,filelength)
  734.     ENDIF
  735.  
  736.     /* We dont need the filehandle any longer */
  737.     Close(fh)
  738.     fh:=NIL
  739.  
  740.   ELSE
  741.     Raise("open")
  742.   ENDIF
  743.  
  744. EXCEPT
  745.   IF fh THEN Close(fh)
  746.   IF buffer THEN Dispose(buffer)
  747.   ReThrow()
  748.  
  749. ENDPROC version,base,buffer
  750. ->\\
  751.  
  752.  
  753. /* Search for a version-string in a file
  754. ** Parameter:
  755. **   buffer       - Contents of file
  756. **   bufferlength - length of buffer in bytes
  757. ** Returns version,base
  758. ** if no version-string was found then -1 is returned as version
  759. ** Example: version=81259, base=10000 means
  760. **          Versionnumber is 81259/10000=8.1259
  761. */
  762. PROC getversion(buffer:PTR TO CHAR,bufferlength)
  763. ->// "getversion()"
  764. DEF version=-1:REG,base:REG
  765.  
  766.       MOVEA.L buffer,A0           -> A0..buffer
  767.       MOVE.L  bufferlength,D0     -> D0..bufferlength
  768.       SUBQ.L  #1,D0
  769.       MOVE.B  #"$",D1
  770.       MOVE.L  #"VER:",D2
  771. gv_search_loop:
  772.       SUBQ.L  #1,D0               
  773.       BLT.W   gv_ende             -> bufferend reached ?
  774.       CMP.B   (A0)+,D1
  775.       BNE.S   gv_search_loop      -> Found a "$" ?
  776.       CMP.L   (A0),D2             -> Yes, then next characters="VER:"
  777.       BNE.S   gv_search_loop
  778.  
  779.       SUBQ.L  #4,D0               -> We have found a version-string
  780.       BLT.S   gv_ende
  781.       ADDQ.L  #4,A0               -> skip "VER:"
  782.  
  783.       MOVE.B  #" ",D1
  784. gv_skipspaces1:                   -> skip all spaces before programname
  785.       SUBQ.L  #1,D0
  786.       BLT.S   gv_ende             -> bufferend reached ?
  787.       CMP.B   (A0)+,D1
  788.       BEQ.S   gv_skipspaces1
  789.       ADDQ.L  #1,D0               -> all spaces skipped; we have gone
  790.       SUBQ.L  #1,A0               -> one step too far.
  791.  
  792. gv_skipname:                      -> skip programname
  793.       SUBQ.L  #1,D0
  794.       BLT.S   gv_ende             -> bufferend reached ?
  795.       CMP.B   (A0)+,D1
  796.       BNE.S   gv_skipname
  797.       ADDQ.L  #1,D0               -> go one step back
  798.       SUBQ.L  #1,A0
  799.  
  800. gv_skipspaces2:                   -> skip spaces before version-number
  801.       SUBQ.L  #1,D0
  802.       BLT.S   gv_ende             -> bufferend reached ?
  803.       CMP.B   (A0)+,D1
  804.       BEQ.S   gv_skipspaces2
  805.       ADDQ.L  #1,D0               -> go one step back
  806.       SUBQ.L  #1,A0
  807.  
  808.       MOVEQ   #0,version
  809.       MOVE.B  #".",D1
  810.       MOVEQ   #0,D2
  811. gv_getversion1:                   -> get version until we found a "."
  812.       SUBQ.L  #1,D0
  813.       BLT.S   gv_ende             -> bufferend reached ?
  814.       MOVE.B  (A0)+,D2
  815.       SUBI.L  #"0",D2             -> Transform character "0".."9" into number
  816.       MULU.W  #10,version         -> version:=version*10
  817.       ADD.L   D2,version          ->                    +number
  818.       CMP.B   (A0),D1
  819.       BNE.S   gv_getversion1
  820.       SUBQ.L  #1,D0               -> skip "."
  821.       ADDQ.L  #1,A0
  822.  
  823.       MOVE.B  #" ",D1
  824.       MOVEQ   #1,base
  825. gv_getversion2:                   -> get reversion
  826.       SUBQ.L  #1,D0
  827.       BLT.S   gv_ende             -> bufferend reached ?
  828.       MOVE.B  (A0)+,D2
  829.       SUBI.L  #"0",D2             -> Transform character "0".."9" into number
  830.       MULU.W  #10,version         -> version:=version*10
  831.       MULU.W  #10,base            -> base:=base*10
  832.       ADD.L   D2,version          ->                    +number
  833.       CMP.B   (A0),D1
  834.       BNE.S   gv_getversion2
  835.  
  836. gv_ende:
  837.  
  838. ENDPROC version,base
  839. ->\\
  840.  
  841.